/*
 * Copyright (c)  2020,  DataPipeline
 * All rights reserved.
 *
 * Id:ClassDesc.java   2020-07-18 15:53 wanglijun
 */
package cn.datacare.orm.database;

import cn.datacare.orm.annotation.ColumnIgnore;
import cn.datacare.orm.annotation.InsertIgnore;
import cn.datacare.orm.annotation.UpdateIgnore;
import cn.datacare.orm.annotation.builder.AttributeBuilderHolder;
import cn.datacare.orm.concurrent.CaseInsensitiveHashMap;
import cn.datacare.orm.concurrent.CaseInsensitiveOrderSet;
import cn.datacare.orm.conversion.NameConversion;
import cn.datacare.orm.type.JavaType;
import cn.datacare.orm.util.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2020
 * </p>
 * <p>
 * Company/Department: DataPipeline
 * </p>
 *
 * @author wanglijun
 * @version 1.0
 * @since 2020-07-18 15:53
 */
public class ClassDesc {
    private Class targetClass;
    private TableDesc table;
    private NameConversion nc;
    private Set<String> properties = new CaseInsensitiveOrderSet<>();
    //记录table和pojo的交集
    private Set<String> cols = new CaseInsensitiveOrderSet<>();
    List<String> idProperties = new ArrayList<>(3);
    List<String> idCols = new ArrayList<>(3);
    Map<String, Object> idMethods = new CaseInsensitiveHashMap<>();
    Set<String> dateTypes = new CaseInsensitiveOrderSet<>();

    ClassAnnotation ca = null;

    public ClassDesc(Class c, TableDesc table, NameConversion nc) {
        this.targetClass = c;
        ca = ClassAnnotation.getClassAnnotation(c);
        PropertyDescriptor[] ps = ca.getPropertyDescriptor();

        Set<String> ids = table.getIdNames();
        CaseInsensitiveHashMap<String, PropertyDescriptor> tempMap = new CaseInsensitiveHashMap<String, PropertyDescriptor>();

        for (PropertyDescriptor p : ps) {
            //所有属性必须有getter和setter
            if (p.getReadMethod() != null && BeanUtils.getWriteMethod(p, c) != null) {
                String property = p.getName();
                String col = nc.getColName(c, property);
                if (col != null) {
                    tempMap.put(col, p);
                }
            }
        }


        //取交集
        for (String col : table.getCols()) {
            if (tempMap.containsKey(col)) {
                cols.add(col);
                PropertyDescriptor p = (PropertyDescriptor) tempMap.get(col);
                properties.add(p.getName());
                Method readMethod = p.getReadMethod();
                Class retType = readMethod.getReturnType();
                if (java.util.Date.class.isAssignableFrom(retType)
                        || java.util.Calendar.class.isAssignableFrom(retType)) {
                    dateTypes.add(p.getName());
                }

                if (ids.contains(col)) {
                    //保持同一个顺序
                    idProperties.add(p.getName());
                    idCols.add(col);
                    idMethods.put(p.getName(), readMethod);

                }

            }
        }


    }

    /**
     * 用于代码生成，只有tabledesc
     *
     * @param table
     * @param nc
     */
    public ClassDesc(TableDesc table, NameConversion nc) {
        this.table = table;
        this.nc = nc;
        for (String colName : table.getCols()) {
            String prop = nc.getPropertyName(colName);
            this.properties.add(prop);
            ColDesc colDes = table.getColDesc(colName);
            if (JavaType.isDateType(colDes.getSqlType())) {
                dateTypes.add(prop);
            }
            this.cols.add(colName);
        }
        for (String name : table.getIdNames()) {
            this.idProperties.add(nc.getPropertyName(name));
        }


    }


    public boolean isDateType(String property) {
        return dateTypes.contains(property);
    }

    public List<String> getIdAttrs() {
        return this.idProperties;
    }

    public List<String> getIdCols() {
        return idCols;
    }

    public Set<String> getAttrs() {
        return properties;
    }


    public Set<String> getInCols() {
        return this.cols;
    }

    public Map<String, Object> getIdMethods() {
        return this.idMethods;
    }

    public boolean isInsertIgnore(String attrName) {
        ColumnIgnoreStatus ignore = ca.attrIgnores.get(attrName);
        if (ignore == null) {
            return false;
        }
        return ignore.insertIgnore;
    }

    public boolean isUpdateIgnore(String attrName) {
        ColumnIgnoreStatus ignore = ca.attrIgnores.get(attrName);
        if (ignore == null) {
            return false;
        }
        return ignore.updateIgnore;
    }

    public String getVersionProperty() {
        return ca.versionProperty;
    }

    public Class getTargetClass() {
        return targetClass;
    }

    public void setTargetClass(Class targetClass) {
        this.targetClass = targetClass;
    }

    public String getLogicDeleteAttrName() {
        return ca.logicDeleteAttrName;
    }

    public int getLogicDeleteAttrValue() {
        return ca.logicDeleteAttrValue;
    }

    public int getInitVersionValue() {
        return ca.initVersionValue;
    }

    public CaseInsensitiveHashMap<String, AttributeBuilderHolder> getColHandlers() {
        return ca.colHandlers;
    }

    static class ColumnIgnoreStatus {
        public boolean insertIgnore;
        public boolean updateIgnore;

        public ColumnIgnoreStatus(ColumnIgnore ignore) {
            insertIgnore = ignore.insert();
            updateIgnore = ignore.update();
        }

        public ColumnIgnoreStatus(InsertIgnore ig, UpdateIgnore ug) {
            insertIgnore = ig != null;
            updateIgnore = ug != null;
        }

    }
}
